package org.zoomdev.zoom;

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import org.zoomdev.zoom.common.exceptions.ZoomException;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class MapJsonReader {
    private static final JsonFactory jsonFactory = FactoryHolder.jsonFactory;

    private MapJsonReader() {

    }

    public static Map read(String str) throws IOException {
        try (JsonParser jp = jsonFactory.createJsonParser(str)) {
            jp.nextToken();
            return parseMap(jp);
        }
    }

    public static Map read(InputStream str) throws IOException {
        try (JsonParser jp = jsonFactory.createJsonParser(str)) {
            jp.nextToken();
            return parseMap(jp);
        }
    }

    public static Map read(Reader str) throws IOException {
        try (JsonParser jp = jsonFactory.createJsonParser(str)) {
            jp.nextToken();
            return parseMap(jp);
        }
    }

    static List parseArray(JsonParser jp) throws IOException {
        List list = new ArrayList();
        JsonToken token;
        while ((token = jp.nextToken()) != JsonToken.END_ARRAY) {
            list.add(parseValue(jp, token));
        }
        return list;
    }

    static Object parseValue(JsonParser jp, JsonToken token) throws IOException {
        Object value;
        switch (token) {
            case START_OBJECT:
                value = parseMap(jp);
                break;
            case START_ARRAY:
                value = parseArray(jp);
                break;

            case VALUE_STRING:
                value = jp.getText();
                break;

            case VALUE_NUMBER_INT:
            case VALUE_NUMBER_FLOAT:
                value = jp.getNumberValue();
                break;
            case VALUE_TRUE:
                value = Boolean.TRUE;
                break;
            case VALUE_FALSE:
                value = Boolean.FALSE;
                break;
            case VALUE_NULL:
                value = null;
                break;
            default:
                throw new ZoomException("不正确的json数据类型");
        }
        return value;
    }

    static Map parseMap(JsonParser jp) throws IOException {
        Map map = new HashMap();
        JsonToken t = jp.getCurrentToken();
        if (t == JsonToken.START_OBJECT) {
            t = jp.nextToken();
        }
        for (; t == JsonToken.FIELD_NAME; t = jp.nextToken()) {
            String key = jp.getCurrentName();
            JsonToken token = jp.nextToken(); // 移动到字段值
            map.put(key, parseValue(jp, token));
        }

        return map;
    }
}
